
package com.plian.system.service.sys.user.impl;

import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.plian.Tools.CollectionUtil;
import com.plian.Tools.DateUtil;
import com.plian.Tools.StringUtil;
import com.plian.Tools.Tools;
import com.plian.system.config.RedisUtils;
import com.plian.system.constant.yth.YthConstant;
import com.plian.system.entity.sys.Org;
import com.plian.system.entity.sys.User;
import com.plian.system.entity.sys.UserOrg;
import com.plian.system.mapper.sys.SysUserMapper;
import com.plian.system.model.CommonCode;
import com.plian.system.model.R;
import com.plian.system.service.sys.orgzation.IOrgService;
import com.plian.system.service.sys.user.ISysUserService;
import com.plian.system.service.sys.user.IUserOrgService;
import com.plian.system.vo.sys.UserVO;
import com.plian.system.vo.yth.YthResult;
import com.plian.system.wrapper.sys.UserWrapper;
import lombok.AllArgsConstructor;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 用户 服务实现类
 *
 * @author jianglei
 * @since 2022-01-10
 */
@Service
@AllArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, User> implements ISysUserService {

    private IOrgService orgService;

    private IUserOrgService userOrgService;

    private UserWrapper userWrapper;

    private RedisUtils redisUtils;
    @Override
    public User getByDataSourceId(String dataSource, String dataSourceId) {
        return getOne(Wrappers.<User>lambdaQuery()
                .eq(User::getDataSource, dataSource)
                .eq(User::getDataSourceId, dataSourceId));
    }

    @Override
    public List<User> getByDataSourceIds(String dataSource, List<String> dataSourceIds) {
        return list(Wrappers.<User>lambdaQuery()
                .eq(User::getDataSource, dataSource)
                .in(User::getDataSourceId, dataSourceIds));
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public String ythUserSubmitList(String data) {
        List<UserVO> userList = JSON.parseArray(data, UserVO.class);
        List<User> allOldUserList = list();
        List<String> allUserNamesList = allOldUserList.stream().map(User::getUsername).collect(Collectors.toList());
        List<User> oldUserList = getByDataSourceIds(YthConstant.DATA_NINGBO, userList.stream()
                .filter(user -> StringUtil.isNotBlank(user.getDataSourceId()))
                .map(User::getDataSourceId)
                .collect(Collectors.toList()));
        Map<String, User> oldDataSourceIdUserMap = oldUserList.stream().collect(Collectors.toMap(User::getDataSourceId, user -> user));

        Date now = DateUtil.now();

        List<User> submitUserList = new ArrayList<>();
        Map<String, List<String>> orgUnifiedCodeMap = new HashMap<>();
        List<String> successIds = new ArrayList<>();
        List<String> failIds = new ArrayList<>();
        for (UserVO userVO : userList){
            if (CollectionUtil.isNotEmpty(userVO.getOrgDataSourceIds())){
                orgUnifiedCodeMap.put(userVO.getDataSourceId(), userVO.getOrgDataSourceIds());
            }
            if (CollectionUtil.isNotEmpty(oldDataSourceIdUserMap) &&
                    oldDataSourceIdUserMap.containsKey(userVO.getDataSourceId())){
                User oldUser = oldDataSourceIdUserMap.get(userVO.getDataSourceId());
                if (StringUtil.isNotBlank(userVO.getName())){
                    oldUser.setName(userVO.getName());
                }
                oldUser.setPhone(userVO.getPhone());
                oldUser.setUpdateTime(now);
                submitUserList.add(oldUser);
                successIds.add(userVO.getDataSourceId());
                userOrgService.removeByUserId(oldUser.getId());
            }else {
                //新增用户 校验username
                if (allUserNamesList.contains(userVO.getUsername())){
                    failIds.add(userVO.getDataSourceId());
                    continue;
                }
                User user = userWrapper.voToEntity(userVO);
                user.setCreateDate(now);
                user.setDataSource(YthConstant.DATA_NINGBO);
                submitUserList.add(user);
                successIds.add(user.getDataSourceId());
            }
        }
        saveOrUpdateBatch(submitUserList);

        if (CollectionUtil.isNotEmpty(orgUnifiedCodeMap)){
            //保存用户组织关系
            List<Org> orgList = orgService.getYthOrgList();
            Map<String, String> orgDataSourceIdMap = orgList.stream().collect(Collectors.toMap(Org::getDataSourceId, Org::getId));
            Map<String, String> map = submitUserList.stream().collect(Collectors.toMap(User::getDataSourceId, User::getId));
            List<UserOrg> addUserOrgList = new ArrayList<>();
            orgUnifiedCodeMap.forEach((k, v) -> {
                if (map.containsKey(k)){
                    addUserOrgList.addAll(orgDataSourceIdMapToUserOrg(orgDataSourceIdMap, map.get(k), v));
                }
            });
            userOrgService.saveBatch(addUserOrgList);
        }
        //ythResult转换成json字符串
        return JSON.toJSONString(YthResult.builder().successIds(successIds).failIds(failIds).failReason(CollectionUtil.isNotEmpty(failIds) ? "用户账号已存在" : null).build());
    }

    @Override
    public String ythUserRemove(String data) {
        List<String> dataSourceIds = JSON.parseArray(data, String.class);
        if (CollectionUtil.isEmpty(dataSourceIds)){
            return JSON.toJSONString(YthResult.builder().build());
        }
        List<User> oldUserList = getByDataSourceIds(YthConstant.DATA_NINGBO, dataSourceIds);
        if (CollectionUtil.isEmpty(oldUserList)){
            return JSON.toJSONString(YthResult.builder().failIds(dataSourceIds).failReason("账号不存在").build());
        }
        List<String> oldDataSourceIds = oldUserList.stream().map(User::getDataSourceId).collect(Collectors.toList());
        List<String> successIds = new ArrayList<>();
        List<String> failIds = new ArrayList<>();
        for (String dataSourceId : dataSourceIds){
            if (oldDataSourceIds.contains(dataSourceId)){
                successIds.add(dataSourceId);
            }else {
                failIds.add(dataSourceId);
            }
        }
        removeByIds(oldUserList.stream().map(User::getId).collect(Collectors.toList()));
        return JSON.toJSONString(YthResult.builder().successIds(successIds).failIds(failIds).failReason(CollectionUtil.isNotEmpty(failIds) ? "账号不存在" : null).build());
    }

    @Override
    public String ythUserDetails(String data) {
        List<String> dataSourceIds = JSON.parseArray(data, String.class);
        if (CollectionUtil.isEmpty(dataSourceIds)){
            return JSON.toJSONString(new ArrayList<>());
        }
        List<User> userList = getByDataSourceIds(YthConstant.DATA_NINGBO, dataSourceIds);
        List<Org> orgList = orgService.getYthOrgList();
        Map<String, String> orgDataSourceMap = orgList.stream().collect(Collectors.toMap(Org::getId, Org::getDataSourceId));
        if (CollectionUtil.isEmpty(userList)){
            return JSON.toJSONString(new ArrayList<>());
        }
        List<UserVO> userVOList = new ArrayList<>();
        for (User user : userList){
            UserVO userVO = new UserVO();
            userVO.setDataSourceId(user.getDataSourceId());
            userVO.setUsername(user.getUsername());
            userVO.setName(user.getName());
            userVO.setPhone(user.getPhone());
            List<UserOrg> userOrgList = userOrgService.getByUserId(user.getId());
            if (CollectionUtil.isNotEmpty(userOrgList)){
                List<String> orgDataSourceIds = new ArrayList<>();
                for (UserOrg userOrg : userOrgList){
                    if (orgDataSourceMap.containsKey(userOrg.getOrgId())){
                        orgDataSourceIds.add(orgDataSourceMap.get(userOrg.getOrgId()));
                    }
                }
                userVO.setOrgDataSourceIds(orgDataSourceIds);
            }
            userVOList.add(userVO);
        }
        return JSON.toJSONString(userVOList);
    }


    private List<UserOrg> orgDataSourceIdMapToUserOrg(Map<String, String> orgDataSourceIdMap, String userId, List<String> orgDataSourceIds){
        List<UserOrg> userOrgList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(orgDataSourceIds)){
            for (String orgDataSourceId : orgDataSourceIds){
                if (orgDataSourceIdMap.containsKey(orgDataSourceId)){
                    UserOrg userOrg = new UserOrg();
                    userOrg.setUserId(userId);
                    userOrg.setOrgId(orgDataSourceIdMap.get(orgDataSourceId));
                    userOrgList.add(userOrg);
                }
            }
        }
        return userOrgList;
    }

    @Override
    public Map<String, String> getSourceId(){
        List<User> userList = list(new LambdaQueryWrapper<User>().eq(User::getDataSource, 3));
        return userList.stream().collect(Collectors.toMap(User::getDataSourceId, User::getId));
    }

    @Override
    public Map<String, User> getSourceEntity(){
        List<User> userList = list(new LambdaQueryWrapper<User>().eq(User::getDataSource, 3));
        return userList.stream().collect(Collectors.toMap(User::getDataSourceId, m -> m));
    }

    @Override
    public R checkToken(String token){
        R obj = R.success();
        //判断有无Token
        if(Tools.isEmpty(token)){
            obj=new R(CommonCode.UNTOKEN);
            return obj;
        }
        // 判断redis中是否存在
        if (redisUtils.hasKey(token)){
            return obj;
        }
        // 获取 token 中的 user id
        List<String> Audience;
        DecodedJWT jwt;
        try {
            jwt = JWT.decode(token);
            Audience = jwt.getAudience();
        }catch (JWTDecodeException e){
             obj=new R(CommonCode.UNTOKEN);
            log.error(ExceptionUtils.getFullStackTrace(e));
            return obj;
        }
        if(Audience==null || Audience.size()<=0){
             obj=new R(CommonCode.UNAUTHORISE);
            return obj;
        }
        String userid=Audience.get(0);
        User user = getById(userid);
        if (user == null) {
            obj=new R(CommonCode.UNTOKEN);
            return obj;
        }
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
        try {
            jwtVerifier.verify(token);
        } catch (JWTVerificationException e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            obj=new R(CommonCode.UNTOKEN);
            return obj;
        }
        //获取过期时间,存入token
        Map<String, Claim> claims = jwt.getClaims();
        Optional.ofNullable(claims.get("exp")).ifPresent(exp ->{
            Date date = exp.asDate();
            long time = (date.getTime() - new Date().getTime()) / 1000;
            redisUtils.set(token, System.currentTimeMillis(), time);
        });
        return obj;
    }

}
